#include "Vector3D.hpp"
/*#include <stdio.h>
#include <iosfwd>*/
#include <limits>

using namespace klasPhysics;


// Zeroing functions
void Vector3D::Zero()
{
	x = 0.0, y = 0.0, z = 0.0;
}

bool Vector3D::IsZero() const
{
	return IsEqual(x, 0.0) && IsEqual(y, 0.0) && IsEqual(z, 0.0);
}
// -------------------------------------------------------------------




// Normalizes the vector
void Vector3D::Normalize()
{
	Real vector_length = this->Length();

	if (vector_length > std::numeric_limits<Real>::epsilon())
	{
		this->x /= vector_length;
		this->y /= vector_length;
		this->z /= vector_length;
	}
}
// -------------------------------------------------------------------





// Functions that return data based upon this vector
// Returns the vector perpendicular to this one on the specified axis @Param axis | AXIS_X AXIS_Y AXIS_Z
Vector3D Vector3D::Perp(iReal axis)
{
	switch(axis)
	{
	case AXIS_X:
		return Vector3D(-x, y, z);
	case AXIS_Y:
		return Vector3D(x, -y, z);
	case AXIS_Z:
		return Vector3D(x, y, -z);
	}
}			

// Returns the length of this vector.
Real Vector3D::Length() const
{
	return sqrt(x * x + y * y + z * z);
}

// Returns the square of the length, thus avoiding a costly sqrt call.
Real Vector3D::LengthSq() const
{
	return (x * x) + (y * y) + (z * z);
}

// Returns the dot product of this and the other vector
Real Vector3D::Dot(const Vector3D &other) const
{
	return ((x * other.x) + (y * other.y) + (z * other.z));
}

// Returns the cross product of this vector and the other 
Vector3D  Vector3D::Cross(const Vector3D &other) const
{
	Real x = y*other.z - z*other.y;
	Real y = z*other.x - x*other.z;
	Real z = x*other.y - y*other.x;

	return Vector3D(x, y, z);
}

// Returns the euclidean distance between this vector and the other one
Real Vector3D::Distance(const Vector3D &other) const
{
	Real xSeparation = other.x - x,
		 ySeparation = other.y - y,
		 zSeparation = other.z - z;

	return sqrt((xSeparation * xSeparation) + (ySeparation * ySeparation) + (zSeparation * zSeparation));
}

// Truncates a vector so that its length does not exceed max
inline void Vector3D::Truncate(Real max)
{
	if (this->Length() > max)
	{
		this->Normalize();

		*this *= max;
	}
}

//  Given a normalized vector this method reflects the vector it
//  is operating upon. (like the path of a ball bouncing off a wall)
inline void Vector3D::Reflect(const Vector3D& normal)
{
	*this += 2.0 * this->Dot(normal) * normal.GetReverse();
}

// Returns the reverse of this vector
inline Vector3D Vector3D::GetReverse() const
{
	return Vector3D(-this->x, -this->y, -this->z);
}

// -------------------------------------------------------------------





bool Vector3D::operator ==(const Vector3D &rhs)
{
	return (IsEqual(x, rhs.x) && IsEqual(y, rhs.y) && IsEqual(z, rhs.z));
}

bool Vector3D::operator !=(const Vector3D &rhs)
{
	return !(IsEqual(x, rhs.x) && IsEqual(y, rhs.y) && IsEqual(z, rhs.z));
}



// -------------------------------------------------------------------
